/* 
 * File:   BodyFactoryStatic.cpp
 * Author: mauro
 * 
 * Created on 13 de octubre de 2014, 18:08
 */

#include "BodyFactoryStatic.h"
#include "../Define/DefaultValues.h"

BodyFactoryStatic::BodyFactoryStatic() {
}

BodyFactoryStatic::BodyFactoryStatic(b2World& world) {
    this->world = &world;
}

b2Body* BodyFactoryStatic::getBody(int sides, b2Vec2* pos, b2Vec2* size, float scale, float rotation) {

    SBSLog* myLogFile;
    myLogFile->getInstance(MY_LOG_MODE);

    if (sides == 1 || sides == 2) {
        myLogFile->writeInLog(0, "[0] La cantidad de lados es mayor a 0 y menor a 3, se creara un circulo por defecto\n");
    } else if (sides > 6) {
        myLogFile->writeInLog(0, "[0] La cantidad de lados es mayor a 6, se creara un hexagono por defecto\n");
    }

    //Fixture    
    b2FixtureDef fixtureDef;
    fixtureDef.userData = (void*) IS_FLOOR;
    fixtureDef.filter.groupIndex = GROUPINDEXPLATFORM;

    b2BodyDef bodyDef;
    bodyDef.type = b2_staticBody;
    bodyDef.position.Set(pos->x, pos->y);

    if (sides < 3 || sides == 4) {
        bodyDef.angle = rotation;
    } else {
        bodyDef.angle = -0.315 + rotation; // por como se dibuja esta inclinado
    }

    b2Body *body = this->world->CreateBody(&bodyDef);

    b2Vec2 points[sides];

    int x, y;
    //Circulo = 0    
    if (sides < 3) {

        b2CircleShape circle;
        circle.m_radius = scale;

        fixtureDef.shape = &circle;

        body->CreateFixture(&fixtureDef);
        myLogFile->writeInLog(0, "[0] Se ha creado un circulo estatico en el mundo\n");
    }

    if (sides == 4) {

        b2PolygonShape rect;
        rect.SetAsBox(size->x, size->y);

        fixtureDef.shape = &rect;

        body->CreateFixture(&fixtureDef);
        myLogFile->writeInLog(0, "[0] Se ha creado un poligono dinamico en el mundo de 4 lados\n");
    }

    if (sides >= 5 || sides == 3) {

        if (sides > 6) {
            sides = 6;
        }

        b2PolygonShape poly;
        float x, y;
        float side = ((2 * scale) * sin(M_PI / sides));

        for (int i = 0; i < sides; ++i) {
            x = side * cos(2 * M_PI * i / sides);
            y = side * sin(2 * M_PI * i / sides);
            points[i].Set(x, y);
        }

        poly.Set(points, sides);
        fixtureDef.shape = &poly;
        body->CreateFixture(&fixtureDef);

        myLogFile->writeInLog(0, "[0] Se ha creado un poligono estatico en el mundo de ");
        myLogFile->writeInLog(0, to_string(sides));
        myLogFile->writeInLog(0, " lados\n");
    }

    //    if(sides < 3){
    //        body = this->getCircle(pos, scale);
    //    } else {
    //        body = this->getPolygon(pos, scale, size, sides,rotation);
    //    }

    return body;
}

b2Body* BodyFactoryStatic::getBodyParallellogram(b2Vec2* pos, b2Vec2* size, float alpha, float rotation) {

    SBSLog* myLogFile;
    myLogFile->getInstance(MY_LOG_MODE);

    if (size->x < 0 || size->y < 0) {
        myLogFile->writeInLog(2, "[2] El tamaño de la figura es invalido (Base o altura negativo)\n");
    }

    b2BodyDef bodyDef;
    bodyDef.type = b2_staticBody;
    bodyDef.position.Set(pos->x, pos->y);
    bodyDef.angle = rotation;

    b2Body* body = this->world->CreateBody(&bodyDef);

    b2FixtureDef fixtDef;
    fixtDef.filter.groupIndex = GROUPINDEXPLATFORM;

    b2PolygonShape parall;

    float side = (size->y) / sin(alpha) * 2;
    float ady = cos(alpha) * side;

    b2Vec2 points[4]; // paralelogramo = 4 lados

    points[0].Set(ady - (size->x), (-1)*(size->y));
    points[1].Set(ady + (size->x), (-1)*(size->y));
    points[2].Set((size->x), (size->y));
    points[3].Set((-1)*(size->x), (size->y));

    parall.Set(points, 4);
    fixtDef.shape = &parall;
    fixtDef.userData = (void*) IS_FLOOR;

    body->CreateFixture(&fixtDef);

    myLogFile->writeInLog(0, "[0] Se ha creado un paralelogramo estatico en el mundo\n");

    return body;
}

b2Body* BodyFactoryStatic::getBodyTrapezium(b2Vec2* pos, b2Vec2* size, float alpha, float beta, float rotation) {

    b2BodyDef bodyDef;
    bodyDef.type = b2_staticBody;
    bodyDef.position.Set(pos->x, pos->y);
    bodyDef.angle = rotation;

    b2Body* body = this->world->CreateBody(&bodyDef);

    b2FixtureDef fixtDef;
    fixtDef.filter.groupIndex = GROUPINDEXPLATFORM;

    b2PolygonShape trap;

    float adyAlpha = size->y * cos(alpha) / sin(alpha) * 2;
    float adyBeta = size->y * cos(beta) / sin(beta) * 2;

    b2Vec2 points[4];
    points[0].Set((-1) * size->x, size->y);
    points[1].Set(size->x, size->y);
    points[2].Set(size->x - adyBeta, (-1) * size->y);
    points[3].Set(adyAlpha - size->x, (-1) * size->y);

    trap.Set(points, 4);
    fixtDef.shape = &trap;
    fixtDef.userData = (void*) IS_FLOOR;

    body->CreateFixture(&fixtDef);

    SBSLog* myLogFile;
    myLogFile->getInstance(MY_LOG_MODE);
    myLogFile->writeInLog(0, "[0] Se ha creado un trapecio estatico en el mundo\n");

    return body;
}

b2Body* BodyFactoryStatic::getCircle(b2Vec2* pos, float scale) {

    b2BodyDef *bodyDef = new b2BodyDef;
    bodyDef->type = b2_staticBody;
    bodyDef->position.Set(pos->x, pos->y);

    b2Body *body = this->world->CreateBody(bodyDef);
    b2CircleShape *circle = new b2CircleShape;

    circle->m_radius = scale;

    b2FixtureDef *fixtureDef = new b2FixtureDef;
    fixtureDef->shape = circle;
    fixtureDef->userData = (void*) IS_FLOOR;

    body->CreateFixture(fixtureDef);

    SBSLog* myLogFile;
    myLogFile->getInstance(MY_LOG_MODE);
    myLogFile->writeInLog(0, "[0] Se ha creado un circulo estatico en el mundo\n");

    return body;
}

b2Body* BodyFactoryStatic::getPolygon(b2Vec2* pos, float scale, b2Vec2* size, int sides, float rotation) {

    b2Vec2 points[sides];

    //    b2BodyDef *bodyDef = new b2BodyDef;
    b2BodyDef bodyDef;
    bodyDef.type = b2_staticBody;
    bodyDef.position.Set(pos->x, pos->y);

    b2FixtureDef fixtDef;

    fixtDef.userData = (void*) IS_FLOOR;

    if (sides == 4) {
        bodyDef.angle = rotation;
        //        b2PolygonShape* rect = new b2PolygonShape;
        //        rect->SetAsBox(size->x, size->y);
        b2PolygonShape rect;
        rect.SetAsBox(size->x, size->y);
        fixtDef.shape = &rect;

    } else if (sides >= 5 || sides == 3) {

        if (sides > 6) {
            sides = 6;
        }

        bodyDef.angle = -0.315 + rotation; // por como se dibuja esta inclinado
        //        b2PolygonShape* poly = new b2PolygonShape;
        b2PolygonShape poly;
        float x, y;

        float side = ((2 * scale) * sin(M_PI / sides));

        for (int i = 0; i < sides; ++i) {
            x = side * cos(2 * M_PI * i / sides);
            y = side * sin(2 * M_PI * i / sides);
            points[i].Set(x, y);
        }

        poly.Set(points, sides);
        //        poly->Set(points, sides);
        fixtDef.shape = &poly;
    }

    b2Body* body = this->world->CreateBody(&bodyDef);
    body->CreateFixture(&fixtDef);

    SBSLog* myLogFile;
    myLogFile->getInstance(MY_LOG_MODE);
    myLogFile->writeInLog(0, "[0] Se ha creado un poligono estatico en el mundo de ");
    myLogFile->writeInLog(0, to_string(sides));
    myLogFile->writeInLog(0, " lados\n");

    return body;
}

b2Body* BodyFactoryStatic::getBonus(b2Vec2 *pos, b2Vec2 *size, int id) {

    b2FixtureDef fixtureDef;
    fixtureDef.filter.groupIndex = GROUPINDEXENEMY;
    switch (id) {
        case BONUS_FLASH:
            fixtureDef.userData = (void*) IS_BONUS_FLASH;
            break;
        case BONUS_LIFE:
            fixtureDef.userData = (void*) IS_BONUS_LIFE;
            break;
    }

    b2BodyDef bodyDef;
    bodyDef.type = b2_staticBody;
    bodyDef.position.Set(pos->x, pos->y);
    bodyDef.fixedRotation = true;
    b2Body *body = this->world->CreateBody(&bodyDef);
    b2Vec2 points[4];
    int x, y;

    b2PolygonShape box;
    box.SetAsBox(size->x, size->y);

    fixtureDef.shape = &box;
    fixtureDef.density = 5.0f;
    fixtureDef.friction = FRICTION;
    body->CreateFixture(&fixtureDef);

    b2FixtureDef footFixt;
    b2PolygonShape footPoly;

    footFixt.isSensor = true;
    float sensorW = size->x;
    float sensorH = size->y;

    footPoly.SetAsBox(sensorW, sensorH, b2Vec2(0, size->y), 0);
    footFixt.shape = &footPoly;
    body->CreateFixture(&footFixt);

    SBSLog* myLogFile;
    myLogFile->getInstance(MY_LOG_MODE);
    myLogFile->writeInLog(0, "[0] Se creo un bonus en el mundo\n");

    return body;
}

BodyFactoryStatic::~BodyFactoryStatic() {
    //    printf ("Destructor FactoryStatic \n");
}

